import { keepDecimalFixed } from "../../utils";
import { CircularQueue } from "../../lib/quant/common/CircularQueue";
import { Kline, Indicator } from "../../lib/quant/interface";

export type VectorResult = {
  min: number;
  max: number;
  vector: number[];
};
/**
 * 向量化
 */
export class Vector implements Indicator {
  buffer: CircularQueue<Kline>;
  result: CircularQueue<VectorResult>;
  period: number;
  maxHistoryLength = 1000;
  constructor({
    period,
    maxHistoryLength
  }: {
    period: number;
    maxHistoryLength?: number;
  }) {
    this.maxHistoryLength = maxHistoryLength || this.maxHistoryLength;
    this.period = period;
    this.buffer = new CircularQueue(period + 1);
    this.result = new CircularQueue(this.maxHistoryLength);
  }

  /**
   * 归一化
   */
  normalize() {
    let max = this.buffer.get(0).high;
    let min = this.buffer.get(0).low;

    //  更新最大最小
    for (let i = 1; i < this.buffer.size(); i++) {
      const current = this.buffer.get(i);
      if (current.high > max) {
        max = current.high;
      } else if (current.low < min) {
        min = current.low;
      }
    }
    const vector: number[] = new Array(this.period).fill(1);
    // 归一化处理
    for (let i = 0; i < this.buffer.size() - 1; i++) {
      const current = this.buffer.get(i);
      vector[i] = keepDecimalFixed((current.close - min) / (max - min), 6);
    }

    return {
      min: min,
      max: max,
      vector
    };
  }
  add(data: Kline) {
    if (!("high" in data) || !("low" in data)) {
      console.warn(`high or low not in ${data}`);
      return;
    }
    // 添加到临时数组中
    this.buffer.push(data);
    if (this.result.getLast() === undefined) {
      const vector: number[] = new Array(this.period).fill(0);
      vector[0] = keepDecimalFixed((data.close - data.low) / (data.high - data.low), 6)
      const result = {
        min: data.low,
        max: data.high,
        vector: vector
      };
      this.result.push(result);
      return result;
    }
    const result = this.normalize();
    this.result.push(result);
    return result;
  }

  updateLast(data: Kline) {
    if (!("high" in data) || !("low" in data)) {
      console.warn(`high or low not in ${data}`);
      return;
    }
    if (this.result.getLast() === undefined) {
      const vector: number[] = new Array(this.period).fill(0);
      vector[0] = keepDecimalFixed((data.close - data.low) / (data.high - data.low), 6)
      const result = {
        min: data.low,
        max: data.high,
        vector: vector
      };
      this.result.push(result);
      return result;
    }
    // this.buffer.update(this.buffer.size() - 1, data);
    // const result = this.normalize();
    // // 更新最后一个
    // this.result.update(this.result.size() - 1, result);
    // return result;
  }

  getValue(index = -1) {
    if (index < 0) {
      return this.result.get(this.result.size() + index);
    }
    return this.result.get(index);
  }
}
